<?php

/**
 * This file is part of Webman AI.
 *
 * @author    walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link      http://www.workerman.net/
 */

namespace plugin\ai\app\handler\driver;

use Workerman\Http\Client;
use Workerman\Http\Response;

class Midjourney extends Base
{

    /**
     * @var string api地址
     */
    protected $api = 'http://127.0.0.1:8080';

    protected $apiSecret;

    protected $allowAllFast = true;

    protected $allRelax = false;

    protected $hideSpeedOptions = false;

    /**
     * @param array $options
     */
    public function __construct(array $options = [])
    {
        parent::__construct($options);
        $this->apiSecret = !empty($options['apiSecret']) ? $options['apiSecret'] : $options['apikey'] ?? '';
        $this->allowAllFast = $options['allowAllFast'] ?? true;
        $this->allRelax = $options['allRelax'] ?? false;
        $this->hideSpeedOptions = $options['hideSpeedOptions'] ?? false;
    }

    /**
     * Speech
     * @param $data
     * @param $options
     * @return void
     */
    public function imagine($data, $options)
    {
        $this->post($this->api . "/image/imagine", $data, $options);
    }

    /**
     * @param $data
     * @param $options
     * @return void
     */
    public function action($data, $options)
    {
        $this->post($this->api . "/image/action", $data, $options);
    }

    /**
     * @param $data
     * @param $options
     * @return void
     */
    public function status($data, $options)
    {
        $this->get($this->api . "/task/fetch", $data, $options);
    }

    /**
     * @param $data
     * @param $options
     * @param $url
     * @return void
     */
    protected function post($url, $data, $options)
    {
        $headers = array_merge($this->getHeaders($options), [
            'mj-api-secret' => (string)$this->apiSecret ?: '',
        ]);
        $options = $this->formatOptions($options);
        if ($prompt = $data['prompt'] ?? '') {
            $isVip = $data['allowFast'] ?? false;
            $useRelax = $this->allRelax || (!$isVip && !$this->allowAllFast);
            // 所有人员强制使用慢速作图 或者 非vip用户强制使用慢速作图
            if ($this->hideSpeedOptions || $useRelax) {
                $prompt = preg_replace(['/--fast/i', '/--relax/'], '', $prompt);
                if (!$this->hideSpeedOptions && $useRelax) {
                    $prompt .= ' --relax';
                }
            }
            $data['prompt'] = $prompt;
        }

        $requestOptions = [
            'method' => 'POST',
            'data' => json_encode($data),
            'headers' => $headers,
            'success' => function (Response $response) use ($options) {
                $options['complete'](static::formatResponse((string)$response->getBody()), $response);
            },
            'error' => function ($exception) use ($options) {
                $options['complete']([
                    'error' => [
                        'code' => 'exception',
                        'message' => $exception->getMessage(),
                        'detail' => (string) $exception
                    ],
                ], new Response(0));
            }
        ];
        $http = new Client();
        $http->request($url, $requestOptions);
    }

    /**
     * @param $data
     * @param $options
     * @param $url
     * @return void
     */
    protected function get($url, $data, $options)
    {
        $headers = array_merge($this->getHeaders($options), [
            'mj-api-secret' => (string)$this->apiSecret ?: '',
        ]);
        $options = $this->formatOptions($options);
        $requestOptions = [
            'method' => 'GET',
            'data' => $data,
            'headers' => $headers,
            'success' => function (Response $response) use ($options) {
                $options['complete'](static::formatResponse((string)$response->getBody()), $response);
            },
            'error' => function ($exception) use ($options) {
                $options['complete']([
                    'error' => [
                        'code' => 'exception',
                        'message' => $exception->getMessage(),
                        'detail' => (string) $exception
                    ],
                ], new Response(0));
            }
        ];
        $http = new Client();
        $http->request($url, $requestOptions);
    }

    /**
     * Format audio response.
     * @param $buffer
     * @return array[]
     */
    public static function formatResponse($buffer): array
    {
        $json = json_decode($buffer, true);
        if ($json) {
            return $json;
        }
        return [
            'code' => 501,
            'msg' => 'Unable to parse response',
            'detail' => $buffer,
            'taskId' => null,
        ];
    }

}